Skip to content

[#24] Trading widget for story page#72

Merged
realproject7 merged 4 commits intomainfrom
task/24-trading-widget
Mar 14, 2026
Merged

[#24] Trading widget for story page#72
realproject7 merged 4 commits intomainfrom
task/24-trading-widget

Conversation

@realproject7
Copy link
Copy Markdown
Owner

Summary

  • P5-2a: New TradingWidget component with buy/sell tabs, amount input, and live price estimates from MCV2_Bond (priceForNextMint/priceForNextBurn)
  • P5-2b: Buy flow — checks ERC-20 allowance, approves PLOT_TOKEN if needed, calls MCV2_Bond.mint() with 3% slippage protection
  • P5-2c: Sell flow — calls MCV2_Bond.burn() with 3% slippage protection
  • Full tx state UI: approving → confirming → pending → done/error with retry
  • All contract addresses from lib/contracts/constants.ts

Fixes #24

Test plan

  • Verify buy/sell flows execute correctly
  • npm run lint and npm run typecheck pass

🤖 Generated with Claude Code

Fixes #24

- P5-2a: TradingWidget component with buy/sell tabs, amount input,
  and estimated cost/return from MCV2_Bond view functions
- P5-2b: Buy flow — checks allowance, approves PLOT_TOKEN if needed,
  calls MCV2_Bond.mint() with 3% slippage protection
- P5-2c: Sell flow — calls MCV2_Bond.burn() with 3% slippage protection
- Shows tx state progression (approving → confirming → pending → done)
- Extended lib/price.ts with mint/burn/approve/allowance ABIs
- All addresses from lib/contracts/constants.ts, reserve label adapts
  to testnet (WETH) vs mainnet ($PLOT)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES

Summary

The UI scaffolding and state handling are reasonable, and CI is green, but the widget is currently built against Mint Club V2 function signatures that do not match the published MCV2_Bond contract interface. As written, the quote reads and trade writes will not execute against the real bond contract.

Findings

  • [high] The estimate calls use priceForNextMint(token, amount) / priceForNextBurn(token, amount), but Mint Club V2's published MCV2_Bond interface exposes quote helpers under different signatures (priceForNextMint(token) and refund/reserve quote helpers), not the 2-arg selectors defined here. That means the widget is computing selectors from a made-up ABI and the live estimate calls will fail at runtime.
    • File: src/components/TradingWidget.tsx:49
    • Suggestion: Replace the custom estimate ABI with the real MCV2_Bond quote/view functions from the deployed contract and wire the widget to those selectors.
  • [high] The transaction ABI is also missing the receiver parameter. Mint Club V2's published mint/burn signatures take four arguments, including a receiver address, but this PR encodes only three args (token, amount, slippage bound). Those writes will target the wrong function selector and revert instead of trading.
    • File: src/components/TradingWidget.tsx:93
    • Suggestion: Update the ABI to the real mint/burn signatures and pass the connected wallet address as the receiver argument.

Decision

Requesting changes because the current contract calls do not match the real MCV2_Bond interface, so the trading widget is not functional yet.

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST CHANGES — missing approval in sell flow.

Bug (blocking): src/components/TradingWidget.tsx:100-113 — The sell flow calls MCV2_Bond.burn() directly without first checking/approving the storyline token. MCV2_Bond needs approval to transfer the user's storyline tokens before burning. The buy flow correctly handles allowance/approve for PLOT_TOKEN, but the sell flow is missing the equivalent for the storyline token (tokenAddress).

Fix: mirror the buy flow's allowance check pattern — check allowance(address, MCV2_BOND) on tokenAddress, approve if insufficient, then call burn().

Minor (non-blocking):

  • lib/rpc is imported for the client-side publicClient, while lib/price.ts uses lib/viem — verify these are intentionally separate (server vs client viem instances).
  • Price estimate query fires on every keystroke with no debounce — could generate excessive RPC calls during fast typing.

Adds required 4th `receiver` parameter to mint() and burn() ABI
signatures and passes connected wallet address as receiver in both
trade flows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES

Summary

The receiver-parameter fix addresses one contract-call issue, but the sell flow is still not executable because it never approves the storyline token before calling MCV2_Bond.burn().

Findings

  • [high] The sell path jumps straight to burn() without checking or approving the user's allowance for tokenAddress. If MCV2_Bond pulls storyline tokens via transferFrom before burning, every sell will revert for users who have not already approved the bond contract.
    • File: src/components/TradingWidget.tsx:100
    • Suggestion: Mirror the buy flow for sells: read allowance(address, MCV2_BOND) on tokenAddress, prompt an approval transaction when needed, and only then call burn().

Decision

Requesting changes because the current sell path is not functional for first-time sellers.

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST CHANGES — sell-side approval still missing.

The receiver parameter fix is good, but the original issue remains: the sell flow (lines ~100-113) calls MCV2_Bond.burn() without checking/approving the storyline token (tokenAddress) to MCV2_BOND. The bond contract calls transferFrom on the storyline token, which requires ERC-20 approval.

Please add the same allowance check + approve pattern used in the buy flow, but for tokenAddress instead of PLOT_TOKEN:

// Check storyline token allowance
const allowance = await publicClient.readContract({
  address: tokenAddress,
  abi: erc20Abi,
  functionName: "allowance",
  args: [address, MCV2_BOND],
});

if (allowance < parsedAmount) {
  setTxState("approving");
  const approveHash = await writeContractAsync({
    address: tokenAddress,
    abi: erc20Abi,
    functionName: "approve",
    args: [MCV2_BOND, parsedAmount],
  });
  await publicClient.waitForTransactionReceipt({ hash: approveHash });
}

Mirrors the buy flow's approve pattern: checks storyline token
allowance for MCV2_BOND and approves if insufficient before calling
burn().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Sell flow now correctly checks storyline token allowance and approves MCV2_BOND before burning — mirrors the buy flow pattern. Receiver parameter added to both mint/burn ABI signatures. Both flows are now complete: buy (approve PLOT_TOKEN → mint) and sell (approve storyline token → burn). Approved.

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES

Summary

The new sell-token approval step is correct, but there is still a blocking ABI mismatch on the quote path. Mint Club V2's published IMCV2_Bond interface exposes getReserveForToken(token, tokensToMint) and getRefundForTokens(token, tokensToBurn) for estimates, not priceForNextMint(token, amount) / priceForNextBurn(token, amount).

Findings

  • [high] The widget's live estimate query is still wired to non-existent selectors, so quote reads will fail at runtime even after the receiver and approval fixes. The canonical interface published by Mint Club V2 defines getReserveForToken and getRefundForTokens as the view functions for these estimates, while this PR continues to call custom priceForNextMint / priceForNextBurn entries.
    • File: src/components/TradingWidget.tsx:46
    • Suggestion: Replace the custom estimate ABI and query logic with the real IMCV2_Bond view functions (getReserveForToken for buy quotes and getRefundForTokens for sell quotes), then apply slippage to those returned reserve/refund amounts.

Decision

Requesting changes because the widget still cannot fetch valid buy/sell estimates from the deployed bond contract.

Switch from custom priceForNextMint/priceForNextBurn to the real
MCV2_Bond view functions: getReserveForToken and getRefundForTokens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Estimate functions correctly updated to getReserveForToken/getRefundForTokens matching the real IMCV2_Bond interface. Consistent across lib/price.ts and TradingWidget. Approved.

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE

Summary

The trading widget now uses the published Mint Club V2 quote functions, includes the required receiver parameter on trades, and handles approval for both buy and sell flows. The PR matches issue #24 and lint-and-typecheck is passing.

Findings

  • none

Decision

Approving because the story-page trading widget is now wired to the canonical IMCV2_Bond interface with working slippage and approval handling for both directions.

@realproject7 realproject7 merged commit cd6fda7 into main Mar 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P5-2] Trading Widget

2 participants